//------------------------------------------------------------------------------
//  Namespace: FruitVentDesign.Controls
//  
//  Function： N/A
//  Name： PasswordInput
//  
//  Ver       Time                     Author
//  0.10      2021/6/21 10:37:16      Benedict Deng
//
//  此代码版权归作者本人FruitVent所有
//  源代码使用协议遵循本仓库的开源协议及附加协议，若本仓库没有设置，则按MIT开源协议授权
//  CSDN博客：https://blog.csdn.net/weixin_39552347
//  源代码仓库：https://gitee.com/fruitvent
//  感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using WPFTemplateLib.Controls.FruitVentDesign.Commands;

namespace WPFTemplateLib.Controls.FruitVentDesign
{
	public class PasswordInput : TextBox
    {
        static PasswordInput()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(PasswordInput), new FrameworkPropertyMetadata(typeof(PasswordInput)));
        }

        private char PWD_CHAR = '●';

        #region HasErrorMessage 验证通过与否字段
        /// <summary>
        /// 验证通过与否字段
        /// </summary>
        public static readonly DependencyProperty HasErrorMessageProperty = DependencyProperty.Register(
            "HasErrorMessage", typeof(bool), typeof(PasswordInput), new FrameworkPropertyMetadata(false,
                FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                new PropertyChangedCallback(OnHasErrorMessagePropertyChanged)));

        private static void OnHasErrorMessagePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var oldValue = (object)args.OldValue;
            var newValue = (object)args.NewValue;

            if (oldValue == newValue)
                return;

            if ((bool)newValue)
            {
                if (obj is FrameworkElement content && content.Parent is Form form)
                {
                    if (form.ItemContainerGenerator.ContainerFromItem(content) is FormItem formItem)
                    {
                        formItem.HasErrorMessage = true;
                        var binding = new Binding(nameof(FormItem.ErrorMessage))
                        {
                            Source = content,
                            Mode = BindingMode.TwoWay,
                            Path = new PropertyPath("(Validation.Errors).CurrentItem.ErrorContent")
                        };
                        formItem.SetBinding(FormItem.ErrorMessageProperty, binding);
                    }
                }
            }
            else
            {
                if (obj is FrameworkElement content && content.Parent is Form form)
                {
                    if (form.ItemContainerGenerator.ContainerFromItem(content) is FormItem formItem)
                    {
                        formItem.HasErrorMessage = false;
                    }
                }
            }
        }

        public bool HasErrorMessage
        {
            get { return (bool)GetValue(HasErrorMessageProperty); }
            set { SetValue(HasErrorMessageProperty, value); }
        }

        public static void SetHasErrorMessage(DependencyObject element, bool value)
        {
            element.SetValue(HasErrorMessageProperty, value);
        }

        public static bool GetHasErrorMessage(DependencyObject element)
        {
            return (bool)element.GetValue(HasErrorMessageProperty);
        }
		#endregion

		#region 密码 Password
		/// <summary>
		/// 密码
		/// </summary>
		public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached(
            "Password", typeof(string), typeof(PasswordInput), new FrameworkPropertyMetadata(string.Empty,
                FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                new PropertyChangedCallback(OnPasswordChanged)));

        private static void OnPasswordChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var oldValue = (object)args.OldValue;
            var newValue = (object)args.NewValue;

            if (oldValue == newValue)
                return;
        }

        public string Password
        {
            get { return (string)GetValue(PasswordProperty); }
            set { SetValue(PasswordProperty, value); }
        }

        public static void SetPassword(DependencyObject element, string value)
        {
            element.SetValue(PasswordProperty, value);
        }

        public static string GetPassword(DependencyObject element)
        {
            return (string)element.GetValue(PasswordProperty);
        }
        #endregion

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            if (dirtyBaseText)
                return;

            string currentText = BaseText;

            int selStart = SelectionStart;
            if (currentText.Length < _password.Length)
            {
                // Remove deleted chars          
                _password = _password.Remove(selStart, _password.Length - currentText.Length);
                SetPassword(this, _password);
            }

            if (!string.IsNullOrEmpty(currentText))
            {
                for (int i = 0; i < currentText.Length; i++)
                {
                    if (currentText[i] != PWD_CHAR)
                    {
                        // Replace or insert char
                        if (BaseText.Length == _password.Length)
                        {
                            _password = _password.Remove(i, 1).Insert(i, currentText[i].ToString());
                        }
                        else
                        {
                            _password = _password.Insert(i, currentText[i].ToString());
                        }
                    }
                }
                SetPassword(this, _password);

				if(IsShowOriginText)
				{
					BaseText = _password;
				}
				else
				{
					BaseText = new string(PWD_CHAR, _password.Length);
				}

                SelectionStart = selStart;
            }
            base.OnTextChanged(e);
        }

        // flag used to bypass OnTextChanged
        private bool dirtyBaseText;

        /// <summary>
        /// Provide access to base.Text without call OnTextChanged 
        /// </summary>
        private string BaseText
        {
            get { return base.Text; }
            set
            {
                dirtyBaseText = true;
                base.Text = value;
                dirtyBaseText = false;
            }
        }

        private string _password = string.Empty;
        public new string Text
        {
            get { return _password; }
            set
            {
                if (_password != value)
                {
                    _password = value;
                    BaseText = new string(PWD_CHAR, value.Length);
                }
            }
        }

        #region PlaceholderProperty 占位符
        /// <summary>
        /// 占位符
        /// </summary>
        public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.Register(
            "Placeholder", typeof(string), typeof(PasswordInput), new FrameworkPropertyMetadata(""));

        public static string GetPlaceholder(DependencyObject d)
        {
            return (string)d.GetValue(PlaceholderProperty);
        }

        public static void SetPlaceholder(DependencyObject obj, string value)
        {
            obj.SetValue(PlaceholderProperty, value);
        }
        #endregion

        #region CornerRadiusProperty Border圆角
        /// <summary>
        /// Border圆角
        /// </summary>
        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(
            "CornerRadius", typeof(CornerRadius), typeof(PasswordInput), new FrameworkPropertyMetadata(new CornerRadius(3)));

        public static CornerRadius GetCornerRadius(DependencyObject d)
        {
            return (CornerRadius)d.GetValue(CornerRadiusProperty);
        }

        public static void SetCornerRadius(DependencyObject obj, CornerRadius value)
        {
            obj.SetValue(CornerRadiusProperty, value);
        }
        #endregion

        #region FocusBorderBrushProperty 焦点边框色，输入控件
        /// <summary>
        /// 焦点边框色，输入控件
        /// </summary>
        public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.Register(
            "FocusBorderBrush", typeof(Brush), typeof(PasswordInput), new FrameworkPropertyMetadata(null));

        public static void SetFocusBorderBrush(DependencyObject element, Brush value)
        {
            element.SetValue(FocusBorderBrushProperty, value);
        }

        public static Brush GetFocusBorderBrush(DependencyObject element)
        {
            return (Brush)element.GetValue(FocusBorderBrushProperty);
        }
        #endregion

        #region MouseOverBorderBrushProperty 鼠标进入边框色，输入控件
        /// <summary>
        /// 鼠标进入边框色，输入控件
        /// </summary>
        public static readonly DependencyProperty MouseOverBorderBrushProperty = DependencyProperty.Register(
            "MouseOverBorderBrush", typeof(Brush), typeof(PasswordInput),
            new FrameworkPropertyMetadata(Brushes.Transparent,
            FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        /// <summary>
        /// Sets the brush used to draw the mouse over brush.
        /// </summary>
        public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value)
        {
            obj.SetValue(MouseOverBorderBrushProperty, value);
        }

        /// <summary>
        /// Gets the brush used to draw the mouse over brush.
        /// </summary>
        public static Brush GetMouseOverBorderBrush(DependencyObject obj)
        {
            return (Brush)obj.GetValue(MouseOverBorderBrushProperty);
        }
        #endregion

        #region AttachContentProperty 附加组件模板
        /// <summary>
        /// 附加内容模板
        /// </summary>
        public static readonly DependencyProperty AttachContentProperty = DependencyProperty.Register(
            "AttachContent", typeof(ControlTemplate), typeof(PasswordInput), new FrameworkPropertyMetadata(null));

        public static ControlTemplate GetAttachContent(DependencyObject d)
        {
            return (ControlTemplate)d.GetValue(AttachContentProperty);
        }
		/// <summary>
		/// 附加内容模板（ControlTemplate 类型）
		/// </summary>
		public static void SetAttachContent(DependencyObject obj, ControlTemplate value)
        {
            obj.SetValue(AttachContentProperty, value);
        }
        #endregion

        #region LabelProperty TextBox的头部Label
        /// <summary>
        /// TextBox的头部Label
        /// </summary>
        public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
            "Label", typeof(string), typeof(PasswordInput), new FrameworkPropertyMetadata(null));

        public static string GetLabel(DependencyObject d)
        {
            return (string)d.GetValue(LabelProperty);
        }
		/// <summary>
		/// TextBox的头部Label内容
		/// </summary>
		public static void SetLabel(DependencyObject obj, string value)
        {
            obj.SetValue(LabelProperty, value);
        }
        #endregion

        #region LabelWidthProperty TextBox的头部Label宽度
        /// <summary>
        /// TextBox的头部Label宽度
        /// </summary>
        public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.RegisterAttached(
            "LabelWidth", typeof(double), typeof(PasswordInput), new FrameworkPropertyMetadata(double.NaN));

        public static double GetLabelWidth(DependencyObject d)
        {
            return (double)d.GetValue(LabelWidthProperty);
        }

        public static void SetLabelWidth(DependencyObject obj, double value)
        {
            obj.SetValue(LabelWidthProperty, value);
        }
        #endregion

        #region LabelTemplateProperty TextBox的头部Label模板
        /// <summary>
        /// TextBox的头部Label模板
        /// </summary>
        public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.Register(
            "LabelTemplate", typeof(ControlTemplate), typeof(PasswordInput), new FrameworkPropertyMetadata(null));

        public static ControlTemplate GetLabelTemplate(DependencyObject d)
        {
            return (ControlTemplate)d.GetValue(LabelTemplateProperty);
        }
		/// <summary>
		/// TextBox的头部Label模板
		/// </summary>
		public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value)
        {
            obj.SetValue(LabelTemplateProperty, value);
        }
        #endregion

        #region AllowClearProperty 清除输入框Text值按钮启用
        /// <summary>
        /// 清除输入框Text值按钮显示与否
        /// </summary>
        public static readonly DependencyProperty AllowClearProperty = DependencyProperty.RegisterAttached(
            "AllowClear", typeof(bool), typeof(PasswordInput), new FrameworkPropertyMetadata(false, AllowClearChanged));

        /// <summary>
        /// Gets the brush used to draw the mouse over brush.
        /// </summary>
        public static bool GetAllowClear(DependencyObject d)
        {
            return (bool)d.GetValue(AllowClearProperty);
        }

        public static void SetAllowClear(DependencyObject obj, bool value)
        {
            obj.SetValue(AllowClearProperty, value);
        }

        private static void AllowClearChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != e.NewValue && d is Button button)
            {
                button.CommandBindings.Add(RoutedUICommands.ClearTextCommandBinding);
            }
        }
		#endregion

		#region [依赖属性] 是否显示明文
		/// <summary>
		/// 是否显示明文
		/// </summary>
		public bool IsShowOriginText
		{
			get => (bool)GetValue(IsShowOriginTextProperty);
			set => SetValue(IsShowOriginTextProperty, value);
		}
		/// <summary>
		/// [依赖属性] 是否显示明文
		/// </summary>
		public static readonly DependencyProperty IsShowOriginTextProperty =
			 DependencyProperty.Register(nameof(IsShowOriginText), typeof(bool), typeof(PasswordInput), new PropertyMetadata(false, IsShowOriginTextChangedCallback));
		/// <summary>
		/// 是否显示明文 变动处理方法
		/// </summary>
		private static void IsShowOriginTextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var control = d as PasswordInput;
			if(control == null) return;

			if((bool)e.NewValue)
			{
				control.BaseText = control.Text;
			}
			else
			{
				control.BaseText = new string(control.PWD_CHAR, control.Text.Length);
			}
		}
		#endregion
	}
}
